package dao;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import logs.Log;

import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.ParsingException;
import nu.xom.Serializer;
import nu.xom.ValidityException;

public abstract class Dao<E> {
	
	protected static Dao<?> instance;
	protected Document document;
	protected Thread dbManager;
	protected String fileName = "";
	protected boolean documentChanged;
	protected int idSequence;
	protected String idSequenceFile = "";
	
	public Dao(String fileName, String idSequenceFile) {
		this.fileName = fileName;
		this.idSequenceFile = idSequenceFile;
		retrieveIdSequence();
		openDocument();
		dbManager = new Thread() {
			
			@Override
			public void run() {
				while (true) {
					Dao<?> dao = Dao.instance;
					if (dao.isDocumentChanged()) {
						dao.saveDocumentToXMLFile();
						dao.setDocumentChanged(false);
					}
					try {
						Thread.sleep(30000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
		};
		instance = this;
		dbManager.start();
	}
	
	protected void retrieveIdSequence() {
		File xml = new File(this.idSequenceFile);
		Builder parser = new Builder();
		Document doc = null;
		try {
			doc = parser.build(xml);
		} catch (ValidityException e) {
			doc = e.getDocument();
		} catch (ParsingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		this.idSequence = Integer.parseInt(doc.getRootElement().getChild(0).getValue());
	}
	
	public void saveDocumentToXMLFile() {
		// save document in appropriate db xml file
		File xml = new File(this.fileName);
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(xml);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		try {
			Serializer serializer = new Serializer(fos, "ISO-8859-1");
			serializer.setIndent(4);
			serializer.setMaxLength(64);
			serializer.write(document);
		} catch (IOException ex) {
			Log.log(document.toXML());// TODO improve
		}
		
		//save idSequence into appropriate xml file
		File xmlIdSeq = new File(this.idSequenceFile);
		FileOutputStream fosIdSeq = null;
		try {
			fosIdSeq = new FileOutputStream(xmlIdSeq);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		Element idSeq = new Element("idSequence");
		idSeq.appendChild(""+this.idSequence);
		Document idSeqDoc = new Document(idSeq);
		try {
			Serializer serializer = new Serializer(fosIdSeq, "ISO-8859-1");
			serializer.setIndent(4);
			serializer.setMaxLength(64);
			serializer.write(idSeqDoc);
		} catch (IOException ex) {
			Log.log(idSeqDoc.toXML());// TODO improve
		}
	}

	protected void openDocument() {
		File xml = new File(this.fileName);
		Builder parser = new Builder();
		try {
			this.document = parser.build(xml);
			this.documentChanged = false;
		} catch (ValidityException e) {
			this.document = e.getDocument();
		} catch (ParsingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public boolean isDocumentChanged() {
		return documentChanged;
	}

	public void setDocumentChanged(boolean documentChanged) {
		this.documentChanged = documentChanged;
	}

	public String getFileName() {
		return fileName;
	}
	
	public abstract E add(E entity);
	public abstract E find(int id);
	public abstract E remove(int id);
	public abstract E update(E entity);
	public abstract List<E> listAll();
}
